﻿using System.Collections;
using System;
using System.Threading;
using CSharp.Libs.Koc.KernelModels;

namespace CSharp.Libs.Koc
{
    public class PostHandler : IDisposable
    {
        #region declarations
        private Kernel _KRNL = null;
        private ArrayList _aryPostItems = null;
        private System.Timers.Timer _tmrPoster = null;

        private DateTime _dtLastSentPost = DateTime.Now;

        private const double TIMER_INTERVAL_DEFAULT = 5000;

        #region events
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="psea"></param>
        /// <history>created  08.03.2012</history>
        public delegate void PostSuccessfulEventHandler(object sender, PostEventArgs psea);
        public event PostSuccessfulEventHandler PostSuccessful;
        private void ThrowPostSuccessfulEvent(
            PostEventArgs psea)
        {
            if (PostSuccessful != null)
            {
                PostSuccessful(this, psea);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="psea"></param>
        /// <history>created  08.03.2012</history>
        public delegate void PostFailedEventHandler(object sender, PostEventArgs psea);
        public event PostFailedEventHandler PostFailed;
        private void ThrowPostFailedEvent(
            PostEventArgs psea)
        {
            if (PostFailed != null)
            {
                PostFailed(this, psea);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="leea"></param>
        /// <history>created  09.03.2012</history>
        public delegate void LogEntryEventHandler(object sender, LogEntryEventArgs leea);
        public event LogEntryEventHandler LogEntry;
        private void ThrowLogEntryEvent(
            LogEntryEventArgs leea)
        {
            if (LogEntry != null)
            {
                LogEntry(this, leea);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="leea"></param>
        /// <history>created  06.06.2012</history>
        public delegate void TimerStartedEventHandler(object sender);
        public event TimerStartedEventHandler TimerStarted;
        private void ThrowTimerStartedEvent()
        {
            if (TimerStarted != null)
            {
                TimerStarted(this);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="leea"></param>
        /// <history>created  06.06.2012</history>
        public delegate void TimerStoppedEventHandler(object sender);
        public event TimerStoppedEventHandler TimerStopped;
        private void ThrowTimerStoppedEvent()
        {
            if (TimerStopped != null)
            {
                TimerStopped(this);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="leea"></param>
        /// <history>created  08.06.2012</history>
        public delegate void ItemsChangedEventHandler(object sender);
        public event ItemsChangedEventHandler ItemsChanged;
        private void ThrowItemsChangedEvent()
        {
            if (ItemsChanged != null)
            {
                ItemsChanged(this);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="leea"></param>
        /// <history>created  09.06.2012</history>
        public delegate void TimerElapsedEventHandler(object sender);
        public event TimerElapsedEventHandler TimerElapsed;
        private void ThrowTimerElapsedEvent()
        {
            if (TimerElapsed != null)
            {
                TimerElapsed(this);
            }
        }
        #endregion
        #endregion



        #region constructor / terminator
        public PostHandler(
            Kernel KRNL)
        {
            _KRNL = KRNL;
            _aryPostItems = new ArrayList();
            _tmrPoster = new System.Timers.Timer(TIMER_INTERVAL_DEFAULT);

            _tmrPoster.Elapsed += new System.Timers.ElapsedEventHandler(_tmrPoster_Elapsed);
        }

        public  void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {             
                // get rid of managed resources
                _KRNL = null;
                _aryPostItems = null;
                _tmrPoster.Stop();
                _tmrPoster.Elapsed -= _tmrPoster_Elapsed;
                _tmrPoster.Dispose();
                _tmrPoster = null;
            }            
            // get rid of unmanaged resources     
        }

        ~PostHandler()
        {
            Dispose(false);
        }
        #endregion



        #region event handlers
        void _tmrPoster_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            //Call Listcheck
            _goThroughPostItemList();
            ThrowTimerElapsedEvent();
        }
        #endregion



        #region private functions
        /// <summary>
        /// 
        /// </summary>
        /// <history>created  04.03.2012</history>
        private void _goThroughPostItemList()
        {
            try
            {
                //prepare main switch
                bool fItemsOpen = false;

                //cycle through PostItems List
                foreach (PostHandlerItem PHI in _aryPostItems)
                {
                    //only touch unsolved Posts that are not active right now
                    if (!PHI.success && !PHI.isPosting)
                    {
                        //set main switch
                        fItemsOpen = true;

                        //Start new thread with post
                        PHI.isPosting = true;
                        Thread thr = new Thread((ParameterizedThreadStart)delegate
                        {
                            _postItem(PHI);
                        });
                        thr.Start();

                        //exit this loop
                        break;
                    }
                }

                //If no work is left, deactivate timer
                if (!fItemsOpen)
                {
                    _tmrPoster.Stop();
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="PHI"></param>
        /// <history>created  07.03.2012</history>
        private void _postItem(
            PostHandlerItem PHI)
        {
            try
            {
                #region logging
                if (_KRNL.LoggingEnabled && _KRNL.LogPostHandler)
                    _KRNL.ML.AddMessage("PostHandler._postItem: try='" + PHI.SubmitCount.ToString() + "' lastSubmit='" + PHI.LastSubmit.ToString() + "'");
                #endregion

                //prepare results
                Hashtable htResult = null;
                string strResult = "";

                //set date and counter
                PHI.LastSubmit = DateTime.Now;
                PHI.SubmitCount++;

                //post command and throw events 
                if (PHI.pcCommand.GetAnswerHashtableAndString(out htResult, out strResult))
                {
                    PHI.success = true;

                    //set parameters
                    PHI.ResultString = strResult;
                    PHI.ResultHashtable = htResult;

                    //throw event
                    ThrowPostSuccessfulEvent(new PostEventArgs(PHI.ID, PHI));
                }
                else
                {
                    //set parameters
                    PHI.ResultString = strResult;

                    //throw event
                    ThrowPostFailedEvent(new PostEventArgs(PHI.ID, PHI));
                }

                #region logging
                if (_KRNL.LoggingEnabled && _KRNL.LogPostHandler)
                    _KRNL.ML.AddMessage("PostHandler._postItem: success='" + PHI.success.ToString() + "' resultString='" + PHI.ResultString.Trim() + "'");
                #endregion

                //finally reset IsPosting
                PHI.isPosting = false;
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }
        #endregion



        #region interface
        #region properties
        public ArrayList PostItems { get { return _aryPostItems; } }

        public bool PostingActive
        {
            get { return _tmrPoster.Enabled; }
            set { _tmrPoster.Enabled = value; }
        }
        #endregion

        #region methods
        public void PostItemsAdd(
            PostHandlerItem PH)
        {
            _aryPostItems.Add(PH);
            ThrowItemsChangedEvent();
        }

        public void PostItemsClear()
        {
            _aryPostItems.Clear();
            ThrowItemsChangedEvent();
        }

        public void StartPosting()
        {
            _tmrPoster.Start();
            ThrowTimerStartedEvent();
        }

        public void StopPosting()
        {
            _tmrPoster.Stop();
            ThrowTimerStoppedEvent();
        }
        #endregion
        #endregion
    }
}
